//
// (C) Copyright 2009 Irantha Suwandarathna (irantha@gmail.com)
// All rights reserved.
//

/* Copyright (c) 2001-2008, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use _in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions _in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer _in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


using System;
using System.Text;
using System.Collections.Generic;

namespace EffiProzDB
{



    /**
     * Defines the constants that are used to identify SQL types for HSQLDB JDBC
     * inteface type reporting. The actual type constant values are equivalent
     * to those defined _in the latest java.sql.Types, where available,
     * or those defined by ansi/iso SQL 200n otherwise. A type sub-identifer
     * has been added to differentiate HSQLDB-specific type specializations.
     *
     * @author  boucherb@users
     * @version 1.7.2
     * @since 1.7.2
     */
    public class Types
    {

        /**
         * Names of types.
         * Used for external, JDBC reporting
         * Used for library and user function arguments
         */
        public const string DecimalClassName = "System.Decimal";
        public const string DateClassName = "System.DateTime";
        public const string TimeClassName = "System.DateTime";
        public const string TimestampClassName = "System.DateTime";

        /**
         * The constant _in the Java programming language, sometimes referred to
         * as a type code, that identifies the generic SQL type
         * <code>ARRAY</code>.
         *
         * @since JDK 1.2
         */
        public  const int ARRAY = 2003;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>BIGINT</code>.
         */
        public const int BIGINT = -5;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>BINARY</code>.
         */
        public const int BINARY = -2;

        /**
         * The constant _in the Java programming language, sometimes referred to
         * as a type code, that identifies the generic SQL type
         * <code>BLOB</code>.
         *
         * @since JDK 1.2
         */
        public const int BLOB = 2004;

        /**
         * The constant _in the Java programming language, somtimes referred to
         * as a type code, that identifies the generic SQL type
         * <code>bool</code>.
         *
         * @since JDK 1.4
         */
        public const int BOOLEAN = 16;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>CHAR</code>.
         */
        public const int CHAR = 1;

        /**
         * The constant _in the Java programming language, sometimes referred to
         * as a type code, that identifies the generic SQL type
         * <code>CLOB</code>
         *
         * @since JDK 1.2
         */
        public const int CLOB = 2005;

        /**
         * The constant _in the Java programming language, somtimes referred to
         * as a type code, that identifies the generic SQL type <code>DATALINK</code>.
         *
         * @since JDK 1.4
         */
        public const int DATALINK = 70;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>DATE</code>.
         */
        public const int DATE = 91;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>DECIMAL</code>.
         */
        public const int DECIMAL = 3;

        /**
         * The constant _in the Java programming language, sometimes referred to
         * as a type code, that identifies the generic SQL type
         * <code>DISTINCT</code>.
         *
         * @since JDK 1.2
         */
        public const int DISTINCT = 2001;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>DOUBLE</code>.
         */
        public const int DOUBLE = 8;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>FLOAT</code>.
         */
        public const int FLOAT = 6;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>INTEGER</code>.
         */
        public const int INTEGER = 4;

        /**
         * The constant _in the Java programming language, sometimes referred to
         * as a type code, that identifies the generic SQL type
         * <code>JAVA_OBJECT</code>.
         *
         * @since JDK 1.2
         */
        public const int JAVA_OBJECT = 2000;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>LONGVARBINARY</code>.
         */
        public const int LONGVARBINARY = -4;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>LONGVARCHAR</code>.
         */
        public const int LONGVARCHAR = -1;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>NULL</code>.
         */
        public const int NULL = 0;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>NUMERIC</code>.
         */
        public const int NUMERIC = 2;

        /**
         * The constant _in the Java programming language that indicates
         * that the SQL type is database-specific and
         * gets mapped to a Java object that can be accessed via
         * the methods <code>getObject</code> and <code>setObject</code>.
         */
        public const int OTHER = 1111;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>REAL</code>.
         */
        public const int REAL = 7;

        /**
         * The constant _in the Java programming language, sometimes referred to
         * as a type code, that identifies the generic SQL type
         * <code>REF</code>.
         *
         * @since JDK 1.2
         */
        public const int REF = 2006;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>SMALLINT</code>.
         */
        public const int SMALLINT = 5;

        /**
         * The constant _in the Java programming language, sometimes referred to
         * as a type code, that identifies the generic SQL type
         * <code>STRUCT</code>.
         *
         * @since JDK 1.2
         */
        public const int STRUCT = 2002;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>TIME</code>.
         */
        public const int TIME = 92;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>TIMESTAMP</code>.
         */
        public const int TIMESTAMP = 93;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>TINYINT</code>.
         */
        public const int TINYINT = -6;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>VARBINARY</code>.
         */
        public const int VARBINARY = -3;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the generic SQL type
         * <code>VARCHAR</code>.
         */
        public const int VARCHAR = 12;

        /**
         * <P>The constant _in the Java programming language, sometimes referred
         * to as a type code, that identifies the recent SQL 200n SQL type
         * <code>XML</code>.
         *
         * @since SQL 200n
         */
        public const int XML = 137;

        /**
         * The default HSQLODB type sub-identifier. This indicates that an
         * HSQLDB type with this sub-type, if supported, is the very closest
         * thing HSQLDB offerers to the JDBC/SQL200n type
         */
        public const int TYPE_SUB_DEFAULT = 1;

        /**
         * The IGNORECASE type sub-identifier. This indicates that an HSQLDB type
         * with this sub-type, if supported,  is the closest thing HSQLDB offerers
         * to the JDBC/SQL200n type, except that case is ignored _in comparisons
         */
        public const int TYPE_SUB_IGNORECASE = TYPE_SUB_DEFAULT << 2;

        /**
         * Every (type,type-sub) combination known _in the HSQLDB context.
         * Not every combination need be supported as a table or procedure
         * column type -- such determinations are handled _in DITypeInfo.
         */
        public static int[,] ALL_TYPES = {
        {
            ARRAY, TYPE_SUB_DEFAULT
        }, {
            BIGINT, TYPE_SUB_DEFAULT
        }, {
            BINARY, TYPE_SUB_DEFAULT
        }, {
            BLOB, TYPE_SUB_DEFAULT
        }, {
            BOOLEAN, TYPE_SUB_DEFAULT
        }, {
            CHAR, TYPE_SUB_DEFAULT
        }, {
            CLOB, TYPE_SUB_DEFAULT
        }, {
            DATALINK, TYPE_SUB_DEFAULT
        }, {
            DATE, TYPE_SUB_DEFAULT
        }, {
            DECIMAL, TYPE_SUB_DEFAULT
        }, {
            DISTINCT, TYPE_SUB_DEFAULT
        }, {
            DOUBLE, TYPE_SUB_DEFAULT
        }, {
            FLOAT, TYPE_SUB_DEFAULT
        }, {
            INTEGER, TYPE_SUB_DEFAULT
        }, {
            JAVA_OBJECT, TYPE_SUB_DEFAULT
        }, {
            LONGVARBINARY, TYPE_SUB_DEFAULT
        }, {
            LONGVARCHAR, TYPE_SUB_DEFAULT
        }, {
            NULL, TYPE_SUB_DEFAULT
        }, {
            NUMERIC, TYPE_SUB_DEFAULT
        }, {
            OTHER, TYPE_SUB_DEFAULT
        }, {
            REAL, TYPE_SUB_DEFAULT
        }, {
            REF, TYPE_SUB_DEFAULT
        }, {
            SMALLINT, TYPE_SUB_DEFAULT
        }, {
            STRUCT, TYPE_SUB_DEFAULT
        }, {
            TIME, TYPE_SUB_DEFAULT
        }, {
            TIMESTAMP, TYPE_SUB_DEFAULT
        }, {
            TINYINT, TYPE_SUB_DEFAULT
        }, {
            VARBINARY, TYPE_SUB_DEFAULT
        }, {
            VARCHAR, TYPE_SUB_DEFAULT
        }, {
            VARCHAR, TYPE_SUB_IGNORECASE
        }, {
            XML, TYPE_SUB_DEFAULT
        }
    };
        /*
         SQL specifies predefined data types named by the following <key word>s:
         CHARACTER, CHARACTER VARYING, CHARACTER LARGE OBJECT, BINARY LARGE OBJECT,
         NUMERIC, DECIMAL, SMALLINT, INTEGER, BIGINT, FLOAT, REAL, DOUBLE PRECISION,
         bool, DATE, TIME, TIMESTAMP, and INTERVAL.
         SQL 200n adds DATALINK _in Part 9: Management of External Data (SQL/MED)
         and adds XML _in Part 14: XML-Related Specifications (SQL/XML)
         */

        // CLI type list from Table 37
        public const int SQL_CHARACTER = 1;
        public const int SQL_CHAR = 1;
        public const int SQL_NUMERIC = 2;
        public const int SQL_DECIMAL = 3;
        public const int SQL_DEC = 3;
        public const int SQL_INTEGER = 4;
        public const int SQL_INT = 4;
        public const int SQL_SMALLINT = 5;
        public const int SQL_FLOAT = 6;
        public const int SQL_REAL = 7;
        public const int SQL_DOUBLE = 8;
        public const int SQL_CHARACTER_VARYING = 12;
        public const int SQL_CHAR_VARYING = 12;
        public const int SQL_VARCHAR = 12;
        public const int SQL_bool = 16;
        public const int SQL_USER_DEFINED_TYPE = 17;
        public const int SQL_ROW = 19;
        public const int SQL_REF = 20;
        public const int SQL_BIGINT = 25;
        public const int SQL_BINARY_LARGE_OBJECT = 30;
        public const int SQL_BLOB = 30;
        public const int SQL_CHARACTER_LARGE_OBJECT = 40;
        public const int SQL_CLOB = 40;
        public const int SQL_ARRAY = 50;     // not predefined
        public const int SQL_MULTISET = 55;     //
        public const int SQL_DATE = 91;
        public const int SQL_TIME = 92;
        public const int SQL_TIMESTAMP = 93;     //
        public const int SQL_TIME_WITH_TIME_ZONE = 94;
        public const int SQL_TIMESTAMP_WITH_TIME_ZONE = 95;     //
        public const int SQL_INTERVAL_YEAR = 101;    //
        public const int SQL_INTERVAL_MONTH = 102;
        public const int SQL_INTERVAL_DAY = 103;
        public const int SQL_INTERVAL_HOUR = 104;
        public const int SQL_INTERVAL_MINUTE = 105;
        public const int SQL_INTERVAL_SECOND = 106;
        public const int SQL_INTERVAL_YEAR_TO_MONTH = 107;
        public const int SQL_INTERVAL_DAY_TO_HOUR = 108;
        public const int SQL_INTERVAL_DAY_TO_MINUTE = 109;
        public const int SQL_INTERVAL_DAY_TO_SECOND = 110;
        public const int SQL_INTERVAL_HOUR_TO_MINUTE = 111;
        public const int SQL_INTERVAL_HOUR_TO_SECOND = 112;
        public const int SQL_INTERVAL_MINUTE_TO_SECOND = 113;

        // These values are not _in table 37 of the SQL CLI 200n FCD, but some
        // are found _in tables 6-9 and some are found _in Annex A1:
        // c Header File SQLCLI.H and/or addendums _in other documents,
        // such as:
        // SQL 200n Part 9: Management of External Data (SQL/MED) : DATALINK
        // SQL 200n Part 14: XML-Related Specifications (SQL/XML) : XML
        public const int SQL_BIT_VARYING = 15;              // is _in SQL99 but removed from 200n
        public const int SQL_DATALINK = 70;
        public const int SQL_UDT = 17;
        public const int SQL_UDT_LOCATOR = 18;
        public const int SQL_BLOB_LOCATOR = 31;
        public const int SQL_CLOB_LOCATOR = 41;
        public const int SQL_ARRAY_LOCATOR = 51;
        public const int SQL_MULTISET_LOCATOR = 56;
        public const int SQL_ALL_TYPES = 0;
        public const int SQL_DATETIME = 9;               // collective name
        public const int SQL_INTERVAL = 10;              // collective name
        public const int SQL_XML = 137;

        // SQL_UDT subcodes
        public const int SQL_DISTINCT = 1;
        public const int SQL_SCTRUCTURED = 2;

        // non-standard type not _in JDBC or SQL CLI
        public const int VARCHAR_IGNORECASE = 100;

        // lookup for types
        // boucherb@users - access changed for metadata 1.7.2
        public static Dictionary<string, int> typeAliases;
        public static Dictionary<int, string> typeNames;
        public static Dictionary<string, string> DotNetTypeNames;

        //  boucherb@users - We can't handle method invocations in
        //                   Function.java or user-defined methods whose parameters
        //                   number class is
        //                   narrower than the corresponding internal
        //                   wrapper
        private static HashSet<Type> illegalParameterClasses;

        static Types()
        {
            typeAliases = new Dictionary<string, int>(50, StringComparer.InvariantCultureIgnoreCase);

            typeAliases.Add("INTEGER", Types.INTEGER);
            typeAliases.Add("INT", Types.INTEGER);
            typeAliases.Add("System.Int32", Types.INTEGER);
            typeAliases.Add("Int32", Types.INTEGER);  
            typeAliases.Add("IDENTITY", Types.INTEGER);
            typeAliases.Add("DOUBLE", Types.DOUBLE);  
            typeAliases.Add("System.Double", Types.DOUBLE);
            typeAliases.Add("System.Single", Types.FLOAT);
            typeAliases.Add("FLOAT", Types.FLOAT);
            typeAliases.Add("REAL", Types.REAL);
            typeAliases.Add("VARCHAR", Types.VARCHAR);
            typeAliases.Add("string", Types.VARCHAR);
            typeAliases.Add("System.String", Types.CHAR);
            typeAliases.Add("CHAR", Types.CHAR);
            typeAliases.Add("System.Char", Types.CHAR);
            typeAliases.Add("CHARACTER", Types.CHAR);
            typeAliases.Add("LONGVARCHAR", Types.LONGVARCHAR);
            typeAliases.Add("VARCHAR_IGNORECASE", VARCHAR_IGNORECASE);
            typeAliases.Add("DATE", Types.DATE);
            typeAliases.Add(DateClassName, Types.DATE);
            typeAliases.Add("TIME", Types.TIME);
            typeAliases.Add("TIMESTAMP", Types.TIMESTAMP);
            typeAliases.Add("DATETIME", Types.TIMESTAMP);
            typeAliases.Add("DECIMAL", Types.DECIMAL);
            typeAliases.Add(DecimalClassName, Types.DECIMAL);
            typeAliases.Add("NUMERIC", Types.NUMERIC);
            typeAliases.Add("BIT", Types.BOOLEAN);
            typeAliases.Add("bool", Types.BOOLEAN);
            typeAliases.Add("System.Bool", Types.BOOLEAN);
            typeAliases.Add("boolean", Types.BOOLEAN);
            typeAliases.Add("TINYINT", Types.TINYINT);
            typeAliases.Add("byte", Types.TINYINT);
            typeAliases.Add("System.Byte", Types.TINYINT);
            typeAliases.Add("SMALLINT", Types.SMALLINT);
            typeAliases.Add("short", Types.SMALLINT);
            typeAliases.Add("System.Int16", Types.SMALLINT);
            typeAliases.Add("Int16", Types.SMALLINT);
            typeAliases.Add("BIGINT", Types.BIGINT);
            typeAliases.Add("long", Types.BIGINT);
            typeAliases.Add("System.Int64", Types.BIGINT);
            typeAliases.Add("Int64", Types.BIGINT);
            typeAliases.Add("BINARY", Types.BINARY);
            typeAliases.Add("[B", Types.BINARY);
            typeAliases.Add("VARBINARY", Types.VARBINARY);
            typeAliases.Add("LONGVARBINARY", Types.LONGVARBINARY);
            typeAliases.Add("OTHER", Types.OTHER);
            typeAliases.Add("OBJECT", Types.OTHER);
            typeAliases.Add("System..Object", Types.OTHER);
            typeAliases.Add("NULL", Types.NULL);
            typeAliases.Add("void", Types.NULL);
            typeAliases.Add("System.Void", Types.NULL);

            //
            typeNames = new Dictionary<int,string>();

            typeNames.Add(Types.NULL, "NULL");
            typeNames.Add(Types.INTEGER, "INTEGER");
            typeNames.Add(Types.DOUBLE, "DOUBLE");
            typeNames.Add(VARCHAR_IGNORECASE, "VARCHAR_IGNORECASE");
            typeNames.Add(Types.VARCHAR, "VARCHAR");
            typeNames.Add(Types.CHAR, "CHAR");
            typeNames.Add(Types.LONGVARCHAR, "LONGVARCHAR");
            typeNames.Add(Types.DATE, "DATE");
            typeNames.Add(Types.TIME, "TIME");
            typeNames.Add(Types.DECIMAL, "DECIMAL");
            typeNames.Add(Types.BOOLEAN, "BOOL");
            typeNames.Add(Types.TINYINT, "TINYINT");
            typeNames.Add(Types.SMALLINT, "SMALLINT");
            typeNames.Add(Types.BIGINT, "BIGINT");
            typeNames.Add(Types.REAL, "REAL");
            typeNames.Add(Types.FLOAT, "FLOAT");
            typeNames.Add(Types.NUMERIC, "NUMERIC");
            typeNames.Add(Types.TIMESTAMP, "TIMESTAMP");
            typeNames.Add(Types.BINARY, "BINARY");
            typeNames.Add(Types.VARBINARY, "VARBINARY");
            typeNames.Add(Types.LONGVARBINARY, "LONGVARBINARY");
            typeNames.Add(Types.OTHER, "OBJECT");

            //
            illegalParameterClasses = new HashSet<Type>();

            illegalParameterClasses.Add(typeof(byte));
            illegalParameterClasses.Add(typeof(short));
            illegalParameterClasses.Add(typeof(float));
            illegalParameterClasses.Add(typeof(Byte));
            illegalParameterClasses.Add(typeof(Int16));
            illegalParameterClasses.Add(typeof(Single));

            //
            DotNetTypeNames = new Dictionary<string,string>();

            DotNetTypeNames.Add(DateClassName, "System.DateTime");
            DotNetTypeNames.Add(DecimalClassName, "System.Decimal");
            DotNetTypeNames.Add("byte", "System.Int32");
            DotNetTypeNames.Add("System.Byte", "System.Int32");
            DotNetTypeNames.Add("short", "System.Int32");
            DotNetTypeNames.Add("System.Short", "System.Int32");
            DotNetTypeNames.Add("int", "System.Int32");
            DotNetTypeNames.Add("System.Int32", "System.Int32");
            DotNetTypeNames.Add("long", "System.Int64");
            DotNetTypeNames.Add("System.Int64", "System.Int64");
            DotNetTypeNames.Add("double", "System.Double");
            DotNetTypeNames.Add("System..Double", "System.Double");
            DotNetTypeNames.Add("bool", "System.Boolean");
            DotNetTypeNames.Add("System.Boolean", "System.Boolean");
            DotNetTypeNames.Add("string", "System.String");
            DotNetTypeNames.Add("System.String", "System.String");
            DotNetTypeNames.Add("void", "System.Void");
            DotNetTypeNames.Add("[B", "[B");
        }

        /**
         * Translates a type name returned from a method into the name of type
         * returned _in a ResultSet
         */
        public static string getFunctionReturnClassName(string methodReturnType)
        {

            string name = null;
            DotNetTypeNames.TryGetValue(methodReturnType, out name);

            return name == null ? methodReturnType
                                : name;
        }

        /**
         * `
         *
         * @param type string
         * @return java.sql.Types int value
         * @throws  HsqlException
         */
        public static int getTypeNr(string type)
        {
            int i = int.MinValue;
            if (!typeAliases.TryGetValue(type, out i))
            {

                Trace.check(false, Trace.WRONG_DATA_TYPE, type);
            }

            return i;
        }

        /**
         * Returns SQL type string for a java.sql.Types int value
         */
        public static string getTypeString(int type)
        {
            string tname = null;

            if (typeNames.TryGetValue(type, out tname))
                return tname;

            return null;
        }

        /**
         * Returns SQL type string for a java.sql.Types int value
         */
        public static string getTypeString(int type, int precision, int scale)
        {

            string s = (String)typeNames[type];

            if (precision != 0 && acceptsPrecisionCreateParam(type))
            {
                StringBuilder sb = new StringBuilder(s);

                sb.Append(Token.T_OPENBRACKET);
                sb.Append(precision);

                if (scale != 0 && acceptsScaleCreateParam(type))
                {
                    sb.Append(Token.T_COMMA);
                    sb.Append(scale);
                }

                sb.Append(Token.T_CLOSEBRACKET);

                return sb.ToString();
            }

            return s;
        }

        /**
         * Retieves the type number corresponding to the class
         * of an IN, IN OUT or OUT parameter.  <p>
         *
         * This method:getTypeNr to return OTHER for
         * primitive arrays, classes that directly implement
         * java.io.Serializable and non-primitive arrays whose
         * base component : java.io.Serializable,
         * allowing, for instance, arguments and return types of
         * primitive arrays, ISerializable objects and arrays,
         * of ISerializable objects.  Direct primitive types
         * other than those mapping directly to the internal
         * wrapper form are not yet handled.  That is, HSQLDB
         * cannot yet properly deal with CALLs involving methods
         * with primitive byte, short, float or their
         * corresponding wrappers, due to the way internal
         * conversion works and lack of detection and narrowing
         * code _in Function to allow this.  In other words,
         * passing _in or retrieving any of the mentioned types
         * always causes conversion to a wider internal wrapper
         * which is genrally incompatible under reflective
         * invocation, resulting _in an ArgumentException.
         *
         * @param  c a Class instance
         * @return java.sql.Types int value
         * @throws  HsqlException
         */
         public static int getParameterTypeNr(System.Type c)
        {

            string name;
            int type;

            if (c == null)
            {
                Trace.doAssert(false, "c is null");
            }

            if (c == typeof(void))
            {
                return Types.NULL;
            }

            if (illegalParameterClasses.Contains(c))
            {
                throw Trace.error(Trace.WRONG_DATA_TYPE,
                                  Trace.UNSUPPORTED_PARAM_CLASS, c.Name);
            }

            name = c.Name;
            type = int.MinValue;
            typeAliases.TryGetValue(name, out type);

            if (type == int.MinValue)
            {

                // ensure all nested types are serializable
                // byte[] is already covered as BINARY _in typeAliases
                if (c.IsArray)
                {
                    while (c.IsArray)
                    {
                        c = c.GetElementType();
                    }

                    if (c.IsPrimitive || c.IsSerializable)
                    {
                        type = OTHER;
                    }
                }
                else if (c.IsSerializable)
                {
                    type = OTHER;
                }
            }

            Trace.check(type != int.MinValue, Trace.WRONG_DATA_TYPE, name);

            return type;
        }

        /*
            static bool areSimilar(int t1, int t2) {

                if (t1 == t2) {
                    return true;
                }

                if (isNumberType(t1)) {
                    return isNumberType(t2);
                }

                if (isCharacterType(t1)) {
                    return isCharacterType(t2);
                }

                if (isBinaryType(t1)) {
                    return isBinaryType(t2);
                }

                return false;
            }

            static bool haveSameInternalRepresentation(int t1, int t2) {

                if (t1 == t2) {
                    return true;
                }

                if (isCharacterType(t1)) {
                    return isCharacterType(t2);
                }

                if (isBinaryType(t1)) {
                    return isBinaryType(t2);
                }

                switch (t1) {

                    case TINYINT :
                    case SMALLINT :
                    case INTEGER : {
                        switch (t2) {

                            case TINYINT :
                            case SMALLINT :
                            case INTEGER : {
                                return true;
                            }
                            default : {
                                return false;
                            }
                        }
                    }
                    case FLOAT :
                    case REAL :
                    case DOUBLE : {
                        switch (t2) {

                            case FLOAT :
                            case REAL :
                            case DOUBLE : {
                                return true;
                            }
                            default : {
                                return false;
                            }
                        }
                    }
                    case DECIMAL :
                    case NUMERIC : {
                        switch (t2) {

                            case DECIMAL :
                            case NUMERIC : {
                                return true;
                            }
                            default : {
                                return false;
                            }
                        }
                    }
                    default : {
                        return false;
                    }
                }
            }

            static bool isExactNumberType(int type) {

                switch (type) {

                    case BIGINT :
                    case DECIMAL :
                    case INTEGER :
                    case NUMERIC :
                    case SMALLINT :
                    case TINYINT :
                        return true;

                    default :
                        return false;
                }
            }

            static bool isStrictlyIntegralNumberType(int type) {

                switch (type) {

                    case BIGINT :
                    case INTEGER :
                    case SMALLINT :
                    case TINYINT :
                        return true;

                    default :
                        return false;
                }
            }

            static bool isApproximateNumberType(int type) {

                switch (type) {

                    case DOUBLE :
                    case FLOAT :
                    case REAL :
                        return true;

                    default :
                        return false;
                }
            }

            public static bool isBinaryType(int type) {

                switch (type) {

                    case BINARY :

                    case BLOB :
                    case LONGVARBINARY :
                    case VARBINARY :
                        return true;

                    default :
                        return false;
                }
            }

        */
        public static bool isDatetimeType(int type)
        {

            switch (type)
            {

                case DATE:
                case TIME:
                case TIMESTAMP:
                    return true;

                default:
                    return false;
            }
        }

        /**
         * Types that accept precition params _in column definition or casts.
         * We ignore the parameter _in many cases but accept it for compatibility
         * with other engines. CHAR, VARCHAR and VARCHAR_IGNORECASE params
         * are used when the sql.enforce_strict_types is true.
         *
         */
        public static bool acceptsPrecisionCreateParam(int type)
        {

            switch (type)
            {

                case BINARY:
                case BLOB:
                case CHAR:
                case CLOB:

                //            case LONGVARBINARY :
                //            case LONGVARCHAR :
                case VARBINARY:
                case VARCHAR:
                case VARCHAR_IGNORECASE:
                case DECIMAL:
                case NUMERIC:
                case FLOAT:
                case TIMESTAMP:
                case TIME:
                    return true;

                default:
                    return false;
            }
        }

        public static int numericPrecisionCreateParamRadix(int type)
        {

            switch (type)
            {

                case Types.DECIMAL:
                case Types.NUMERIC:
                    return 10;

                case FLOAT:
                    return 2;

                default:

                    // to mean NOT APPLICABLE (i.e. NULL)
                    return 0;
            }
        }

        public static bool acceptsScaleCreateParam(int type)
        {

            switch (type)
            {

                case Types.DECIMAL:
                case Types.NUMERIC:
                    return true;

                default:
                    return false;
            }
        }

        public static bool isNumberType(int type)
        {

            switch (type)
            {

                case BIGINT:
                case DECIMAL:
                case DOUBLE:
                case FLOAT:
                case INTEGER:
                case NUMERIC:
                case REAL:
                case SMALLINT:
                case TINYINT:
                    return true;

                default:
                    return false;
            }
        }

        public static bool isCharacterType(int type)
        {

            switch (type)
            {

                case CHAR:
                case CLOB:
                case LONGVARCHAR:
                case VARCHAR:
                case VARCHAR_IGNORECASE:
                    return true;

                default:
                    return false;
            }
        }

        public static string getTypeName(int type)
        {

            switch (type)
            {

                case Types.ARRAY:
                    return "ARRAY";

                case Types.BIGINT:
                    return "BIGINT";

                case Types.BINARY:
                    return "BINARY";

                case Types.BLOB:
                    return "BLOB";

                case Types.BOOLEAN:
                    return "BOOL";

                case Types.CHAR:
                    return "CHAR";

                case Types.CLOB:
                    return "CLOB";

                case Types.DATALINK:
                    return "DATALINK";

                case Types.DATE:
                    return "DATE";

                case Types.DECIMAL:
                    return "DECIMAL";

                case Types.DISTINCT:
                    return "DISTINCT";

                case Types.DOUBLE:
                    return "DOUBLE";

                case Types.FLOAT:
                    return "FLOAT";

                case Types.INTEGER:
                    return "INTEGER";

                case Types.JAVA_OBJECT:
                    return "JAVA_OBJECT";

                case Types.LONGVARBINARY:
                    return "LONGVARBINARY";

                case Types.LONGVARCHAR:
                    return "LONGVARCHAR";

                case Types.NULL:
                    return "NULL";

                case Types.NUMERIC:
                    return "NUMERIC";

                case Types.OTHER:
                    return "OTHER";

                case Types.REAL:
                    return "REAL";

                case Types.REF:
                    return "REF";

                case Types.SMALLINT:
                    return "SMALLINT";

                case Types.STRUCT:
                    return "STRUCT";

                case Types.TIME:
                    return "TIME";

                case Types.TIMESTAMP:
                    return "TIMESTAMP";

                case Types.TINYINT:
                    return "TINYINT";

                case Types.VARBINARY:
                    return "VARBINARY";

                case Types.VARCHAR:
                    return "VARCHAR";

                case Types.VARCHAR_IGNORECASE:
                    return "VARCHAR_IGNORECASE";

                case Types.XML:
                    return "XML";

                default:
                    return null;
            }
        }

        /**
         * A reasonable/customizable number to avoid the shortcomings/defects
         * associated with doing a dynamic scan of results to determine
         * the value.  In practice, it turns _out that single query yielding
         * widely varying values for display size of CHAR and VARCHAR columns
         * on repeated execution results _in patently poor usability, as some fairly
         * high-profile, otherwise "enterprise-quality" RAD tools depend on
         * on the first value returned to lay _out forms and limit the size of
         * single line edit controls, set corresponding local datastore storage
         * sizes, etc. In practice, It also turns _out that many tools (due to
         * the original lack of PreparedStatement.getMetaData() _in JDK 1.1) emulate
         * a SQL_DESCRIBE by executing a query hopefully guaranteed to return no
         * or very few rows for example: select ... from ... where 1=0.
         * Using the dynamic scan of 1.7.2 RC5 and previous, therefore, the
         * minimum display size value (1) was often being generated during
         * a tool's describe phase.  Upon subsequent "real" retrievals, some
         * tools complain that CHAR and VARCHAR result values exceeded the
         * originally reported display size and refused to fetch further values.
         */
        public static int _MAX_CHAR_OR_VARCHAR_DISPLAY_SIZE =
            MAX_CHAR_OR_VARCHAR_DISPLAY_SIZE();

        // So that the variable can be both public const and
        // customizable through system properties if required.
        //
        // 32766 (0x7ffe) seems to be a magic number over which several
        // rather high-profile RAD tools start to have problems
        // regarding layout and allocation stress.  It is gently
        // recommended that LONGVARCHAR be used for larger values _in RAD
        // tool layout & presentation use cases until such time as we provide
        // true BLOB support (at which point, LONGVARCHAR will most likely become
        // an alias for CLOB).
        //
        // Most GUI tools seem to handle LONGVARCHAR gracefully by:
        //
        // 1.) refusing to directly display such columns _in graphical query results
        // 2.) providing other means to retrieve and display such values
        private static int MAX_CHAR_OR_VARCHAR_DISPLAY_SIZE()
        {

            try
            {
                return int.Parse(
                    Environment.GetEnvironmentVariable("hsqldb.max_char_or_varchar_display_size"));
            }
            catch (Exception)
            {
                return 32766;
            }
        }

        public static int getMaxDisplaySize(int type)
        {

            switch (type)
            {

                case Types.BINARY:
                case Types.LONGVARBINARY:
                case Types.LONGVARCHAR:
                case Types.OTHER:
                case Types.VARBINARY:
                case Types.XML:
                    return int.MaxValue;    // max string length

                case Types.CHAR:
                case Types.VARCHAR:
                    return _MAX_CHAR_OR_VARCHAR_DISPLAY_SIZE;

                case Types.BIGINT:              // PowerBuilder barfs, wants 19

                    // ...not our problem, tho,
                    // according to JDBC
                    return 20;                   // precision + "-".Length ;

                case Types.BOOLEAN:
                    return 5;                    // Math.max("true".Length ,"false".Length);

                case Types.DATALINK:
                    return 20004;                // same as precision

                case Types.DECIMAL:
                case Types.NUMERIC:
                    return 646456995;            // precision + "-.".Length 

                case Types.DATE:
                    return 10;                   // same as precision

                case Types.INTEGER:
                    return 11;                   // precision + "-".Length ;

                case Types.FLOAT:
                case Types.REAL:
                case Types.DOUBLE:
                    return 23;                   // String.valueOf(-Double.MaxValue).Length ;

                case Types.TIME:
                    return 8;                    // same as precision

                case Types.SMALLINT:
                    return 6;                    // precision + "-".Length ;

                case Types.TIMESTAMP:
                    return 29;                   // same as precision

                case Types.TINYINT:
                    return 4;                    // precision + "-".Length ;

                default:
                    return 0;                    // unknown
            }
        }

        public static bool isSearchable(int type)
        {

            switch (type)
            {

                case Types.ARRAY:
                case Types.BLOB:
                case Types.CLOB:
                case Types.JAVA_OBJECT:
                case Types.STRUCT:
                case Types.OTHER:
                    return false;

                default:
                    return true;
            }
        }

        public static bool isCaseSensitive(int type)
        {

            switch (type)
            {

                case Types.ARRAY:
                case Types.BLOB:
                case Types.CLOB:
                case Types.DISTINCT:
                case Types.JAVA_OBJECT:
                case Types.NULL:
                case Types.REF:
                case Types.STRUCT:
                    return false;

                case Types.CHAR:
                case Types.VARCHAR:
                case Types.DATALINK:
                case Types.LONGVARCHAR:
                case Types.OTHER:
                case Types.XML:
                    return true;

                case Types.VARCHAR_IGNORECASE:
                default:
                    return false;
            }
        }

        public static bool isUnsignedAttribute(int type)
        {

            switch (type)
            {

                case Types.BIGINT:
                case Types.DECIMAL:
                case Types.DOUBLE:
                case Types.FLOAT:
                case Types.INTEGER:
                case Types.NUMERIC:
                case Types.REAL:
                case Types.SMALLINT:
                case Types.TINYINT:
                    return false;

                default:
                    return true;
            }
        }

        public static int getPrecision(int type)
        {

            switch (type)
            {

                case Types.BINARY:
                case Types.CHAR:
                case Types.LONGVARBINARY:
                case Types.LONGVARCHAR:
                case Types.OTHER:
                case Types.VARBINARY:
                case Types.VARCHAR:
                case Types.XML:
                    return int.MaxValue;

                case Types.BIGINT:
                    return 19;

                case Types.BOOLEAN:
                    return 1;

                case Types.DATALINK:

                    // from SQL CLI spec.  TODO:  Interpretation?
                    return 20004;

                case Types.DECIMAL:
                case Types.NUMERIC:

                    // int.MaxValue bit 2's complement number:
                    // (int.MaxValue-1) / ((ln(10)/ln(2)) bits per decimal digit)
                    // See:  java.math.long
                    // - the other alternative is that we could report the numprecradix as 2 and
                    // report int.MaxValue here
                    return 53;

                case Types.DATE:
                case Types.INTEGER:
                    return 10;

                case Types.FLOAT:
                case Types.REAL:
                case Types.DOUBLE:
                    return 17;

                case Types.TIME:
                    return 8;

                case Types.SMALLINT:
                    return 5;

                case Types.TIMESTAMP:
                    return 29;

                case Types.TINYINT:
                    return 3;

                default:
                    return 0;
            }
        }

        public static string getColStClsName(int type)
        {

            switch (type)
            {

                case Types.BIGINT:
                    return "System.Int64";

                case Types.BINARY:
                case Types.LONGVARBINARY:
                case Types.VARBINARY:

                    // but wrapped by org.hsqldb.Binary
                    return "[B";

                case Types.OTHER:

                    // but wrapped by org.hsqldb.JavaObject
                    return "System.Object";

                case Types.BOOLEAN:
                    return "bool";

                case Types.CHAR:
                case Types.LONGVARCHAR:
                case Types.VARCHAR:
                case Types.XML:    //?
                    return "string";

                case Types.DATALINK:
                    return "System.Uri";

                case Types.DATE:
                    return DateClassName;

                case Types.DECIMAL:
                case Types.NUMERIC:
                    return DecimalClassName;

                case Types.DOUBLE:
                case Types.FLOAT:
                case Types.REAL:
                    return "System.Double";

                case Types.INTEGER:
                case Types.SMALLINT:
                case Types.TINYINT:
                    return "int";

                case Types.TIME:
                    return TimeClassName;

                case Types.TIMESTAMP:
                    return TimestampClassName;

                default:
                    return null;
            }
        }
    }
}
